{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Detecting Pneumonia from X-ray images using Deep Java Library"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Disclaimer: this blog post is intended for educational purposes only. The application was developed using experimental code. The result should not be used for any medical diagnoses of pneumonia. This content has not been reviewed or approved by any scientists or medical professionals.*\n",
    "\n",
    "## Introduction\n",
    "In this example, we demonstrate how deep learning (DL) can be used to detect pneumonia from chest X-ray images. This work is inspired by the [Chest X-ray Images Challenge](https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia) on Kaggle and a related [paper](https://www.cell.com/cell/fulltext/S0092-8674\\(18\\)30154-5). In this notebook, we illustrates how artificial intelligence can assist clinical decision making with focus on enterprise deployment. This work leverages a model trained using Keras and TensorFlow with [this Kaggle kernel](https://www.kaggle.com/aakashnain/beating-everything-with-depthwise-convolution). In this blog post, we will focus on generating predictions with this model using [Deep Java Library](https://djl.ai/) (DJL), an open source library to build and deploy DL in Java."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preparation\n",
    "\n",
    "This tutorial requires the installation of Java Kernel. To install the Java Kernel, see the [documentation](https://docs.djl.ai/jupyter/index.html).\n",
    "\n",
    "These are the dependencies we will use:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "// %mavenRepo snapshots https://oss.sonatype.org/content/repositories/snapshots/\n",
    "\n",
    "%maven ai.djl:api:0.12.0\n",
    "%maven ai.djl.tensorflow:tensorflow-api:0.12.0\n",
    "%maven ai.djl.tensorflow:tensorflow-engine:0.12.0\n",
    "%maven ai.djl.tensorflow:tensorflow-model-zoo:0.12.0\n",
    "%maven org.bytedeco:javacpp:1.5.4\n",
    "%maven org.slf4j:slf4j-simple:1.7.26\n",
    "\n",
    "// See https://github.com/deepjavalibrary/djl/blob/master/tensorflow/tensorflow-engine/README.md\n",
    "// for more TensorFlow library selection options\n",
    "%maven ai.djl.tensorflow:tensorflow-native-auto:2.4.1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%loadFromPOM\n",
    "<dependency>\n",
    "    <groupId>com.google.protobuf</groupId>\n",
    "    <artifactId>protobuf-java</artifactId>\n",
    "    <version>3.8.0</version>\n",
    "</dependency>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Import java packages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import ai.djl.inference.*;\n",
    "import ai.djl.modality.*;\n",
    "import ai.djl.modality.cv.*;\n",
    "import ai.djl.modality.cv.util.*;\n",
    "import ai.djl.ndarray.*;\n",
    "import ai.djl.repository.zoo.*;\n",
    "import ai.djl.translate.*;\n",
    "import ai.djl.training.util.*;\n",
    "import ai.djl.util.*;\n",
    "import java.net.*;\n",
    "import java.nio.file.*;\n",
    "import java.util.*;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### set the model URL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "var modelUrl = \"https://resources.djl.ai/demo/pneumonia-detection-model/saved_model.zip\";"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dive deep into Translator\n",
    "\n",
    "To successfully run inference, we need to define some preprocessing and post processing logic to achieve the best \n",
    "prediction result and understandable output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MyTranslator implements Translator<Image, Classifications> {\n",
    "\n",
    "    private static final List<String> CLASSES = Arrays.asList(\"Normal\", \"Pneumonia\");\n",
    "\n",
    "    @Override\n",
    "    public NDList processInput(TranslatorContext ctx, Image input) {\n",
    "        NDManager manager = ctx.getNDManager();\n",
    "        NDArray array = input.toNDArray(manager, Image.Flag.COLOR);\n",
    "        array = NDImageUtils.resize(array, 224).div(255.0f);\n",
    "        return new NDList(array);\n",
    "    }\n",
    "\n",
    "    @Override\n",
    "    public Classifications processOutput(TranslatorContext ctx, NDList list) {\n",
    "        NDArray probabilities = list.singletonOrThrow();\n",
    "        return new Classifications(CLASSES, probabilities);\n",
    "    }\n",
    "\n",
    "    @Override\n",
    "    public Batchifier getBatchifier() {\n",
    "        return Batchifier.STACK;\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see above, the translator resizes the image to 224x224 and normalizes the image by dividing by 255 before feeding it into the model. When doing inference, you need to follow the same pre-processing procedure as was used during training. In this case, we need to match the Keras training code. After running prediction, the model outputs probabilities of each class as an [NDArray](https://javadoc.io/doc/ai.djl/api/latest/index.html). We need to tell the predictor to translate it back to classes, namely “Normal” or \"Pneumonia\".\n",
    "\n",
    "Until this point, all preparation work is done, we can start working on the prediction logic."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Predict using DJL\n",
    "\n",
    "### Load the image\n",
    "We are going to load an CT scanned image of an infected lung from internet "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "var imagePath = \"https://resources.djl.ai/images/chest_xray.jpg\";\n",
    "var image = ImageFactory.getInstance().fromUrl(imagePath);\n",
    "image.getWrappedImage();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load your model\n",
    "Next, we will download the model from `modelUrl`. This will download the model into the DJL cache location"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Criteria<Image, Classifications> criteria =\n",
    "        Criteria.builder()\n",
    "                .setTypes(Image.class, Classifications.class)\n",
    "                .optModelUrls(modelUrl)\n",
    "                .optTranslator(new MyTranslator())\n",
    "                .optProgress(new ProgressBar())\n",
    "                .build();\n",
    "ZooModel model = criteria.loadModel();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Run inference\n",
    "Lastly, we will need to create a predictor using our model and translator. Once we have a predictor, we simply need to call the predict method on our test image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "Predictor<Image, Classifications> predictor = model.newPredictor();\n",
    "Classifications classifications = predictor.predict(image);\n",
    "\n",
    "classifications"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Java",
   "language": "java",
   "name": "java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "14.0.2+12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
